//
//  File.swift
//
//
//  Created by didi on 2022/9/14.
//

import Fluent
import Molecular
import MolecularObjects
import MolecularRedirectObjects
import Vapor

public final class RedirectBuilder: MolecularModuleBuilder {
    override public func build() -> MolecularModule {
        RedirectModule()
    }
}

struct RedirectModule: MolecularModule {
    let router = RedirectRouter()

    func boot(_ app: Application) throws {
        app.migrations.add(RedirectMigrations.v1())

        app.hooks.register(.adminRoutes, use: router.adminRoutesHook)
        app.hooks.register(.apiRoutes, use: router.apiRoutrsHook)
        app.hooks.register(.adminWidgets, use: adminWidgetHook, priority: 200)
        app.hooks.registerAsync(.response, use: responseHook)
        app.hooks.register(.installPermissions, use: installUserPermissionsHook)
    }

    func adminWidgetHook(args: HookArguments) -> [TemplateRepresentable] {
        if args.req.checkPermission(Redirect.permission(for: .detail)) {
            return [RedirectAdminWidgetTemplate()]
        } else { return [] }
    }

    /**
     Apply redirect rules to incoming requests.
     */
    func responseHook(args: HookArguments) async throws -> Response? {
        let req = args.req
        guard let rule = try await RedirectRuleModel.query(on: req.db)
            .filter(\.$source == req.url.path)
            .first() else { return nil }

        let type: RedirectType
        switch UInt(rule.statusCode) {
        case HTTPResponseStatus.movedPermanently.code:
            type = .permanent
        case HTTPResponseStatus.temporaryRedirect.code:
            type = .temporary
        default:
            type = .normal
        }

        return req.redirect(to: rule.destination, type: type)
    }

    func installUserPermissionsHook(args: HookArguments) -> [Permission.Create] {
        var permissions = Redirect.availablePermissions()
        permissions += Redirect.Rule.availablePermissions()
        return permissions.map { .init($0) }
    }
}
